/* C.Mktemp: Make a temporary file name */

#include <string.h>
#include <stdlib.h>
#include "kernel.h"
#include "swis.h"

#include "utils.h"

#define ReadCat	5

/* Create a temporary file name by adding a directory prefix to file.
 * If the external variable temp_dir is not zero, this directory will be
 * used. Otherwise, the following are used, in order.
 *   1. <Tmp$Dir>
 *   2. &.Tmp
 *   3. The current directory.
 * The function returns zero on an error (temp_dir is not a directory, or
 * malloc() failed), otherwise it returns a malloc-ed string containing
 * the required name.
 */

static char *concat (const char *dir, const char *file);

char *temp_dir = 0;

char *mktemp (const char *file)
{
	char *dir;
	char *name;
	char buf[11];
	int len = strlen(file);
	_kernel_osfile_block blk;
	_kernel_swi_regs regs;

	/* Is the supplied filename a pure file name? */
	if (len > 10)
		return 0;

	/* Pad out the supplied filename on the left with a unique ID
	 * (Based on the program start time)
	 */
	if (len < 10 && _kernel_swi(OS_GetEnv,&regs,&regs) == NULL)
	{
		int i;
		char *time = (char *)regs.r[2];

		strcpy(buf,file);

		for (i = len; i < 10; ++i)
		{
			char c = time[(9 - i) >> 1];

			if (i & 1)
				c >>= 4;

			c &= 0x0F;
			buf[i] = "abcdefghijklmnop"[c];
		}

		buf[10] = 0;

		file = buf;
	}

	/* First, try the supplied directory */
	if ( temp_dir )
	{
		if ( _kernel_osfile(ReadCat,temp_dir,&blk) == 2 )
			return concat(temp_dir,file);
		else
		{
			/* Is it a filing system name only? */
			len = strlen(temp_dir);

			if (temp_dir[len-1] != ':')
				return 0;

			/* One extra, just in case file == "", for the '@' */
			name = malloc(len + strlen(file) + 2);

			if (name == 0)
				return 0;

			strcpy(name,temp_dir);
			name[len] = '@';
			name[len+1] = '\0';

			if (_kernel_osfile(ReadCat,name,&blk) != 2)
			{
				free(name);
				return 0;
			}

			strcpy(&name[len],file);
			return name;
		}
	}

	/* Otherwise, go through the list... */

	/* First of all, try <Tmp$Dir> */
	if ((dir = getenv("Tmp$Dir")) != 0)
	{
		if (_kernel_osfile(ReadCat,dir,&blk) == 2)
			return concat(dir,file);
		else
		{
			/* Is it a filing system name only? */
			len = strlen(dir);

			if (dir[len-1] != ':')
				goto no_go;

			/* One extra, just in case file == "", for the '@' */
			name = malloc(len + strlen(file) + 2);

			if (name == 0)
				goto no_go;

			strcpy(name,dir);
			name[len] = '@';
			name[len+1] = '\0';

			if (_kernel_osfile(ReadCat,name,&blk) != 2)
			{
				free(name);
				goto no_go;
			}

			strcpy(&name[len],file);
			return name;
		}
	}

no_go:
	/* No <Tmp$Dir>, so try &.Tmp, if it exists */
	if (_kernel_osfile(ReadCat,"&.Tmp",&blk) == 2)
		return concat("&.Tmp",file);

	/* Out of luck - use the current directory */
	name = malloc(strlen(file)+1);
	if ( name )
		strcpy(name,file);

	return name;
}

static char *concat (const char *dir, const char *file)
{
	char *result = malloc(strlen(dir)+strlen(file)+2);
	char *p = result;

	if ( result == 0 )
		return 0;

	while ( *dir )
		*p++ = *dir++;

	*p++ = '.';
	while ( *file )
		*p++ = *file++;

	*p = '\0';

	return result;
}

/* ----------------------------------------------------------------- */

#ifdef test

#include <stdio.h>

int main (int argc, char *argv[])
{
	char *tmp;

	if ( argc != 2 && argc != 3 )
	{
		fprintf(stderr,"Usage: %s file [dir]\n",argv[0]);
		return 1;
	}

	if ( argc == 3 )
		temp_dir = argv[2];

	tmp = mktemp (argv[1]);

	printf("Temp file = %s\n", tmp ? tmp : "<Not possible>");

	return 0;
}

#endif
